﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using System.Reflection;
using FinPlusAssembler;
using FinPlusInterfaces;

namespace FinPlusCompView
{
    public partial class FinPlusWindow : Window, IFinPlusComp
    {
        [State(Test = true)]
        public string TestString { get { return Adapter.ToString(); } }
        [State(Test = true)]
        public bool IsValid { get; set; }
        [State(Save = true, Test = true, Pin = true)]
        public new double Left { get { return base.Left; } set { base.Left = value; } }
        [State(Save = true, Test = true, Pin = true)]
        public new double Top { get { return base.Top; } set { base.Top = value; } }
        [State(Save = true, Test = true, Pin = true)]
        public new double Height { get { return base.Height; } set { base.Height = value; } }
        [State(Save = true, Test = true, Pin = true)]
        public new double Width { get { return base.Width; } set { base.Width = value; } }
        [State(Test = true)]
        public int ChildrenCount { get { return grid.Children.Count; } }
        [State(Save = true)]
        public double TabPosition { get { return padding.Width; } set { padding.Width = value; } }
        [State(Save = true, Pin = true)]
        public double ScaleValue { get { return _transform.ScaleValue; } set { _transform.ScaleValue = value; } }
        [State(Save = true)]
        public double RotateAngle { get { return _transform.RotateAngle; } set { _transform.RotateAngle = value; } }

        public string Id { get { return _id ?? "Window"; } set { _id = value; } }
        public string LinkedId { get; set; }
        public string Config { get; set; }
        public Env Env { get; set; }
        public IPods Adapter { get { return Children(grid.Children); } }

        private FinPlusTransform _transform;
        private FinPlusControl _view;
        private IPod _state;
        private ITransport _tran;
        private string _id, _user, _templatePath, _callerId;
        private double _mouseStart;
        private bool _isTabShift;
        private Env _env;

        //construct
        public FinPlusWindow(string templatePath, string callerId = "", bool hasHeader = true)
        {
            InitializeComponent();
            _templatePath = templatePath;
            _user = Environment.UserName;
            _callerId = callerId;

            if (!hasHeader)
                header.Visibility = Visibility.Collapsed;

            if (!string.IsNullOrEmpty(_callerId))
                EventListen();
          
            Cursor = ((TextBlock)this.Resources["CPoint"]).Cursor;
        }

        //common control interface
        public void Dock(object control, string dock)
        {
            try
            {
                _view = (FinPlusControl)control;
                _transform = new FinPlusTransform(this, _view);
                grid.Children.Add(_view);
                scalebar.Children.Add(_transform);
            }
            catch (CmdRouterException e)
            {
                IsValid = Level.Error.Log(Id, _templatePath, "", e);
            }
        }

        public void CmdRouting(object s, ExecutedRoutedEventArgs a)
        {
            try
            {
                CmdRouter(a.Parameter.ToString(), s);
            }
            catch (CmdRouterException e)
            {
                IsValid = Level.Error.Log(Id, _templatePath, s.ToString(), e);
            }
        }

        public void CmdRouter(string command, object control)
        {
            try
            {
                var tag = ((Control)control).Tag;
                CmdExecute(IOC.New<IPod>(command, Id, _user, -1, tag == null ? string.Empty : tag.ToString()));
            }
            catch (CmdRouterException e)
            {
                IsValid = Level.Error.Log(Id, _user, command, e);
            }
        }

        public void CmdRouter(string command)
        {
            CmdExecute(IOC.New<IPod>(command, _id, _user));
        }

        public void CmdExecute(IPod command)
        {
            try
            {
                if (_view != null)
                    _view.CmdCapture(command);

                switch ((Cmds)Enum.Parse(typeof(Cmds), command.Name, true))
                {
                    case Cmds.Maximize: Maximize(); break;
                    case Cmds.Minimize: WindowState = WindowState.Minimized; break;
                    case Cmds.Close: Dispose(); break;
                    case Cmds.Home: Home(); break;
                    case Cmds.Save: SaveState(); break;
                    case Cmds.Load: LoadState(); break;
                    case Cmds.Title: if (!_isTabShift) this.DragMove(); break;
                    case Cmds.TitleStartShift: _mouseStart = Mouse.GetPosition(null).X; _isTabShift = true; break;
                    case Cmds.TitleShift: TitleShift(); break;
                    case Cmds.TitleStopShift: _isTabShift = false; break;
                    case Cmds.OnClose: break;
                    default: throw new Exception(string.Format("cmd not recognised {0}", command.Name));
                }
            }
            catch (CmdExecuteException e)
            {
                IsValid = Level.Error.Log(e.Message, e);
            }
        }

        public void Dispose()
        {
            try
            {
                if (_tran != null)
                {
                    _tran.Publish(IOC.New<IMessage>(Cmds.Close.ToString(), _view.LinkedId));
                    _tran.Publish(IOC.New<IMessage>(Cmds.OnClose.ToString(), _callerId));
                }
                if (_view != null)
                    _view.Dispose();
                if (CheckAccess())
                    this.Close();
            }
            catch (Exception e)
            {
                Level.Error.Log(e.Message, e);
            }
        }

        //public
        public IPods Children(UIElementCollection elements)
        {
            var pods = IOC.New<IPods>();
            foreach (var child in elements)
            {
                var value = IOC.New<IPod>();
                value.Object = child;
                pods.Add(value);
            }

            return pods;
        }

        public void SaveState()
        {
            try
            {
                var xmlDoc = _state.ExtractState(Environment.UserName).ToXmlDoc();
                xmlDoc.Save(string.Format("{0}.{1}", _templatePath, FileType.state.ToString()));
            }
            catch (Exception e)
            {
                Level.Warning.Log(e.Message, e);
            }
        }

        public void LoadState()
        {
            try
            {
                _state = IOC.New<IPod>(Id, Id, Environment.UserName);
                _state.Object = finPlusWindow;
                _state.InjectState(_templatePath);
            }
            catch (Exception e)
            {
                Level.Warning.Log(e.Message, e);
            }
        }

        public void SetTitle(string title) {titleText.Text = title.SplitCamelCase();}

        //private
        private void Home()
        {
            WindowState = WindowState.Normal;
            Activate();
            Topmost = true;
            Topmost = false;
            Focus();
        }

        private void Maximize()
        {
            if (WindowState.Equals(WindowState.Minimized))
                WindowState = WindowState.Normal;
            else if (WindowState.Equals(WindowState.Maximized))
                WindowState = WindowState.Normal;
            else if (WindowState.Equals(WindowState.Normal))
                WindowState = WindowState.Maximized;

            Activate();
        }

        private void EventListen()
        {
            var config = Assembly.GetEntryAssembly().Location.Replace(".exe", ".config").ConfigXml(out _env);
            _tran = IOC.New<ITransport>(config["localmessagingsettings"]["address"], int.Parse(config["localmessagingsettings"]["port"]));
            _tran.Listener.MessageRecieved += Message_Event;
            _tran.Listen(_callerId);
        }

        private void TitleShift()
        {
            if (!_isTabShift)
                return;

            var width = _mouseStart - Mouse.GetPosition(null).X;

            if (width > 0) padding.Width = width;
        }

        //cmds
        private enum Cmds { Maximize, Minimize, Close, OnClose, Home, Save, Load, Title, TitleStartShift, TitleShift, TitleStopShift }

        //events
        public void Command_OnInject(object s, PodEventArgs a) { this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { CmdExecute(a.Pod); })); }
        private void Window_OnHome(object s, RoutedEventArgs a) { CmdRouter(Cmds.Home.ToString()); }
        private void Title_MouseDown(object s, MouseButtonEventArgs a) { CmdRouter(Cmds.Title.ToString()); }
        private void Title_MouseRightDown(object s, MouseButtonEventArgs a) { CmdRouter(Cmds.TitleStartShift.ToString()); }
        private void Title_MouseMove(object s, MouseEventArgs a) { CmdRouter(Cmds.TitleShift.ToString()); }
        private void Title_MouseRightButtonUp(object s, MouseEventArgs a) { CmdRouter(Cmds.TitleStopShift.ToString()); }
        private void Mouse_LeftDown(object s, MouseButtonEventArgs a) { this.Activate(); }
        private void Key_Click(object s, KeyEventArgs a)
        {
            if (Keyboard.Modifiers == ModifierKeys.Control)
                if (a.Key == Key.S)
                    CmdRouter(Cmds.Save.ToString());
                else if (a.Key == Key.M)
                    CmdRouter(Cmds.Minimize.ToString());
        }
        private void Message_Event(object s, EventArgs a)
        {
            var cmd = ((MessageEventArgs)a).Message.Value.ToString();
            if (!CheckAccess())
                Dispatcher.Invoke(() => CmdRouter(cmd));
            else
                CmdRouter(cmd);
        }
    }
}